package testrank.predictors;

import java.util.HashMap;
import java.util.Map;

import testrank.Predictor;
import testrank.TestManager;

/**
 * NOTE This predictor is assumed to be the last in TestManager.predictors
 * @author Hagai Cibulski
 *
 */
public class AveragePredictor implements Predictor {

	private static final long serialVersionUID = 1L;
	
	private String name;

	private Map<String, Double> weights;
	
	
	public static AveragePredictor create(String name) {
		AveragePredictor p = new AveragePredictor();
		p.weights = new HashMap<String, Double>();
		p.name = name;
		return p;
	}
	
	public AveragePredictor put(String p, double v) {
		weights.put(p, v);
		return this;
	}
	
	public AveragePredictor() {
		weights = createWeights();
		name = "AVG";
	}
	
	private static Map<String, Double> createWeights() {
		HashMap<String, Double> w = new HashMap<String, Double>();

// PAPER
		w.put("AFFPROP", 85.0);
		w.put("CLCNT", 8.0);
		w.put("VALPROP", 5.0);
		w.put("STKEXCNT", 2.0);

		return w;
	}


	public void putWeight(String predictorName, double weight) {
		weights.put(predictorName, weight);
	}
	
	@Override
	public void begin(String methodSignature, String testSignature) {
	}

	@Override
	public void end(String methodSignature, String testSignature) {
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public double rankFailure(String methodSignature, String testSignature) {
		int len = TestManager.predictors.length;
		Predictor[] predictors = new Predictor[len];
		System.arraycopy(TestManager.predictors, 0, predictors, 0, len);
		
		double sum = 0;
		double totalWeight = 0;
		int total = 0;
		for (Predictor p : predictors) {
			if (p.getName().equals(getName()))
					continue;

			Double weight = weights.get(p.getName());
			if (weight == null)
				continue;

			double score = p.rankFailure(methodSignature, testSignature);
//			if (p == TestManager.affinityPredictor()) {
//				if (score < 0.5) {				
//					score = 0;
//					//continue;
//				}
//				else {
//					score = 1;
//				}
//
////				double sign = Math.signum(score-0.5);
////				double b = Math.sin(Math.abs(score-0.5) * Math.PI);
////				score = (sign*Math.pow(b, 0.1) + 1.0) / 2.0;
//			}

			
// TODO consider only for tests with differential score in comparison to others (e.g. >mean+1std)
			
			sum += score * weight;
			totalWeight += weight;
			total++;
		}
		
		return sum / totalWeight;
	}

}
